﻿using CIS.Web.Common;
using CIS.Web.Models;
using CIS.Web.Properties;
using System;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace CIS.Web.Controllers
{
	[AllowAnonymous]
	[RoutePrefix("PayResult")]
	public class PayResultController : BaseDbController
	{
		public async Task<ActionResult> PaySuccess()
		{
			ViewBag.ReturnUrl = "/ProfilePayment/Index";
			string conferenceId = Session["conferenceId"]?.ToString();
			string payId = Session["payId"]?.ToString();
			string payType = Session["payType"]?.ToString();

			string userName = Session["userName"]?.ToString();
			string password = Session["password"]?.ToString();
			string validateCode = Session["ValidateCode"]?.ToString();

			var conferencePaymentMaster = await DbContext.ConferencePaymentMaster.FirstOrDefaultAsync(x => x.ID == payType);

			// Session过期的情况，使用支付宝返回的支付信息
			if (string.IsNullOrEmpty(payType))
			{
				string outTradeNo = Request.QueryString["out_trade_no"];

				if (string.IsNullOrEmpty(outTradeNo) || outTradeNo.Split(ConstValues.chrUnderline).Length < 4)
				{
					return View("PayFail", this.GetLoginModel(userName, validateCode));
				}

				string[] list = outTradeNo.Split(ConstValues.chrUnderline);
				conferenceId = list[0];
				payId = list[1];
				payType = list[2];//精简版支付类型
				validateCode = list[3];

				var payRecord = await DbContext.ProfilePaymentRecord.FirstOrDefaultAsync(x => x.ID == payId);
				if (payRecord != null)
				{
					userName = payRecord.Creator;
				}
				conferencePaymentMaster = await DbContext.ConferencePaymentMaster.FirstOrDefaultAsync(x => x.ConferenceId == conferenceId && x.ID.Contains(payType));
			}

			if (conferencePaymentMaster == null)
			{
				return View("PayFail", this.GetLoginModel(userName, validateCode));
			}
			payType = conferencePaymentMaster.ID;

			var sysPaymentMaster = await DbContext.SysPaymentMaster.FirstOrDefaultAsync(x => x.ID == conferencePaymentMaster.PayId);
			if (sysPaymentMaster == null)
			{
				return View("PayFail", this.GetLoginModel(userName, validateCode));
			}

			var aFee = string.Empty;
			double? actuallyFee = 0.00;
			if (sysPaymentMaster.PaymentName == ConstValues.PayType.易支付 && sysPaymentMaster.PaymentNameEn == ConstValues.PayType.PayEase)
			{
				aFee = Session["actuallyFee"]?.ToString();
			}
			else if (sysPaymentMaster.PaymentName == ConstValues.PayType.支付宝 && sysPaymentMaster.PaymentNameEn == ConstValues.PayType.AliPay)
			{
				aFee = Request.QueryString["total_fee"];
			}
			else if (sysPaymentMaster.PaymentName == ConstValues.PayType.贝宝 && sysPaymentMaster.PaymentNameEn == ConstValues.PayType.PayPal)
			{
				aFee = Session["actuallyFee"]?.ToString();
			}
			actuallyFee = Utility.ObjectToDouble(aFee);

			if (actuallyFee.HasValue)
			{
				// 验证易支付的返回信息
				if (sysPaymentMaster.PaymentName == ConstValues.PayType.易支付 && sysPaymentMaster.PaymentNameEn == ConstValues.PayType.PayEase)
				{
					var v_pstatus = Request["v_pstatus"]?.ToString().Trim();
					if (v_pstatus != "20")
					{
						return View("PayFail", this.GetLoginModel(userName, validateCode));
					}
				}
				// 验证贝宝的返回信息
				if (sysPaymentMaster.PaymentName == ConstValues.PayType.贝宝 && sysPaymentMaster.PaymentNameEn == ConstValues.PayType.PayPal)
				{
					var item_number = Request["item_number"]?.ToString().Trim();
					var payRecord = await DbContext.ProfilePaymentRecord.FirstOrDefaultAsync(x => x.ID == item_number.Split(ConstValues.chrUnderline)[1]);
					//if (!this.VerifyIPN() || payRecord == null || payRecord.Fee != actuallyFee)
					if (payRecord == null || payRecord.Fee != actuallyFee)
					{
						return View("PayFail", this.GetLoginModel(userName, validateCode));
					}
				}

				var paymentRecord = await DbContext.ProfilePaymentRecord.FirstOrDefaultAsync(x => x.ID == payId);

				if (paymentRecord != null)
				{
					paymentRecord.FeeStatus = true;
				}

				var result = await DbContext.ConferenceAttendenceInfo
					       .FirstOrDefaultAsync(x => x.ID == paymentRecord.AttendenceId);
				if (result != null)
				{
					result.HasPaid = true;
					result.PaymentTypeId = payType;
					result.ActuallyFee = actuallyFee;
					result.UpdateDate = DateTime.Now;
				}

				await DbContext.SaveChangesAsync();

				#region SendMail
				var conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
						.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
							x.MailType == ConstValues.MailType.注册服务邮箱 &&
							x.ConferenceId == conferenceId);

				if (conferenceMailServerMaster == null)
				{
					conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
								x.MailType == ConstValues.MailType.会议邮箱 &&
								x.ConferenceId == conferenceId);
				}

				if (conferenceMailServerMaster != null)
				{
					var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == conferenceId);
					var conferencePayment = await DbContext.ConferencePaymentMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == result.PaymentTypeId);
					var sysPayment = await DbContext.SysPaymentMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == conferencePayment.PayId);

					MailSender sender = new MailSender(conferenceMailServerMaster.MailServer);
					MailAddress from = new MailAddress(conferenceMailServerMaster.Mail);
					MailAddress to = new MailAddress(result.Mail);

					MailMessage message = Utility.GetMailContent(new MailModel
					{
						MailRemark = ConstValues.MailSubject.缴费成功,
						Language = conferenceMaster.IsInternational ? ConstValues.Language.En : ConstValues.Language.Cn,
						UserName = result.FullName,
						ConferenceId = conferenceMaster.ID,
						ConferenceName = conferenceMaster.ConferenceName,
						ConferenceUrl = !string.IsNullOrEmpty(conferenceMaster.HomePageUrl) ? conferenceMaster.HomePageUrl :
							ConstValues.SystemWeb + "/MeetingMain/Index/" + conferenceMaster.ConferenceNickName,
						Currency = paymentRecord.Currency,
						TotalFee = actuallyFee.Value.ToString("N2"),
						PaymentType = conferenceMaster.IsInternational ? sysPayment.PaymentNameEn : sysPayment.PaymentName,
						PaidStatus = Resources.HasPaid,
						PayList = Utility.GetPayDetailList(result.ID, conferenceMaster.ID, conferenceMaster.BenefitStartDate, conferenceMaster.BenefitEndDate)
					});
					message.To.Add(to);

					if (!string.IsNullOrWhiteSpace(conferenceMailServerMaster.CcMail))
					{
						foreach (string cc in conferenceMailServerMaster.CcMail.Split(ConstValues.chrSemicolon))
						{
							if (!string.IsNullOrWhiteSpace(cc) && cc.Contains(ConstValues.chrAt))
							{
								message.Bcc.Add(new MailAddress(cc.Trim()));
							}
						}
					}

					var strMsg = string.Empty;
					var mailTask = Task.Run(() =>
					{
						strMsg = sender.SendMail(from, message, conferenceMailServerMaster.Password);
					});
					if (string.IsNullOrEmpty(strMsg))
					{
						result.HasSendPaid = true;
					}
				}
				#endregion
			}

			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "PaySuccess", conferenceId);

			return View(this.GetLoginModel(userName, validateCode));
		}

		public async Task<ActionResult> PayFail()
		{
			string conferenceId = Session["conferenceId"]?.ToString();
			string payId = Session["payId"]?.ToString();
			string payType = Session["payType"]?.ToString();

			string userName = Session["userName"]?.ToString();
			string password = Session["password"]?.ToString();
			string validateCode = Session["ValidateCode"]?.ToString();

			ViewBag.ReturnUrl = "/ProfilePayment/Index";

			double? actuallyFee = 0.00;
			string aFee = Session["actuallyFee"]?.ToString();
			if (string.IsNullOrEmpty(aFee))
			{
				aFee = Request.QueryString["total_fee"];
			}
			actuallyFee = Utility.ObjectToDouble(aFee);

			if (actuallyFee.HasValue)
			{
				#region SendMail
				var conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
						.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
							x.MailType == ConstValues.MailType.注册服务邮箱 &&
							x.ConferenceId == conferenceId);

				if (conferenceMailServerMaster == null)
				{
					conferenceMailServerMaster = await DbContext.ConferenceMailServerMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常 &&
								x.MailType == ConstValues.MailType.会议邮箱 &&
								x.ConferenceId == conferenceId);
				}

				if (conferenceMailServerMaster != null)
				{
					var paymentRecord = await DbContext.ProfilePaymentRecord
							.FirstOrDefaultAsync(x => x.ID == payId);

					var result = await DbContext.ConferenceAttendenceInfo
						       .FirstOrDefaultAsync(x => x.ID == paymentRecord.AttendenceId);

					var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.ID == conferenceId);

					MailSender sender = new MailSender(conferenceMailServerMaster.MailServer);
					MailAddress from = new MailAddress(conferenceMailServerMaster.Mail);
					MailAddress to = new MailAddress(result.Mail);

					MailMessage message = Utility.GetMailContent(new MailModel
					{
						MailRemark = ConstValues.MailSubject.缴费失败,
						Language = conferenceMaster.IsInternational ? ConstValues.Language.En : ConstValues.Language.Cn,
						ConferenceId = conferenceMaster.ID,
						ConferenceName = conferenceMaster.ConferenceName,
						ConferenceUrl = !string.IsNullOrEmpty(conferenceMaster.HomePageUrl) ? conferenceMaster.HomePageUrl :
							ConstValues.SystemWeb + "/MeetingMain/Index/" + conferenceMaster.ConferenceNickName,
						Currency = paymentRecord.Currency,
						TotalFee = actuallyFee.Value.ToString("N2")
					});
					message.To.Add(to);

					var time = DateTime.Now.ToString("yyyy-MM-dd");

					var registerMail = await DbContext.SysMailMaster.AsNoTracking()
							.FirstOrDefaultAsync(x => x.Remark == ConstValues.MailSubject.缴费失败);

					var conferenceUrl = !string.IsNullOrEmpty(conferenceMaster.HomePageUrl) ? conferenceMaster.HomePageUrl :
							ConstValues.SystemWeb + "/MeetingMain/Index/" + conferenceMaster.ConferenceNickName;

					if (!string.IsNullOrWhiteSpace(conferenceMailServerMaster.CcMail))
					{
						foreach (string cc in conferenceMailServerMaster.CcMail.Split(ConstValues.chrSemicolon))
						{
							if (!string.IsNullOrWhiteSpace(cc) && cc.Contains(ConstValues.chrAt))
							{
								message.Bcc.Add(new MailAddress(cc.Trim()));
							}
						}
					}

					var mailTask = Task.Run(() =>
					{
						sender.SendMail(from, message, conferenceMailServerMaster.Password);
					});
				}
				#endregion
			}

			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName, "PayFail", conferenceId);

			return View(this.GetLoginModel(userName, validateCode));
		}

		public LoginViewModel GetLoginModel(string userName, string validateCode)
		{
			var person = DbContext.SysUserMaster.FirstOrDefault(x => x.UserName == userName);
			var password = StringExtension.Decrypt(person?.Password);

			var model = new LoginViewModel();

			model.AccountName = userName;
			model.Password = password;
			model.ValidateCode = validateCode;

			return model;
		}

		private bool VerifyIPN()
		{
			string strFormValues = Request.Form.ToString();
			string strNewValue;
			string strResponse;
			string serverURL = "https://www.sandbox.paypal.com/cgi-bin/webscr";

			HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serverURL);
			req.Method = "POST";
			req.ContentType = "application/x-www-form-urlencoded";
			strNewValue = strFormValues + "&cmd=_notify-validate";

			req.ContentLength = strNewValue.Length;

			StreamWriter stOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
			stOut.Write(strNewValue);
			stOut.Close();

			StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
			strResponse = stIn.ReadToEnd();
			stIn.Close();

			return strResponse == "VERIFIED";
		}
	}
}